using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Collections.ObjectModel;

namespace Microsoft.MSE
{
    public class ThreadSafeCache<T1, T2>
    {
        static ReaderWriterLockSlim rwlock = new ReaderWriterLockSlim();
        private const int DoNotTimeOut = 0;
        private Dictionary<T1, T2> mCache = new Dictionary<T1, T2>();

        public bool ContainsKey(T1 key)
        {
            bool result = false;
            rwlock.EnterReadLock();
            try
            {
                result = mCache.ContainsKey(key);
            }
            finally
            {
                rwlock.ExitReadLock();
            }
            return result;
        }

        public T2 this[T1 index]
        {
            get
            {
                T2 result;
                rwlock.EnterReadLock();
                try
                {
                    result = mCache[index];
                }
                finally
                {
                    rwlock.ExitReadLock();
                }
                return result;
            }
            set
            {
                rwlock.EnterWriteLock();
                try
                {
                    mCache[index] = value;
                }
                finally
                {
                    rwlock.ExitWriteLock();
                }
            }
        }

        public void Add(T1 key, T2 value)
        {
            rwlock.EnterWriteLock();
            try
            {
                mCache.Add(key, value);
            }
            finally
            {
                rwlock.ExitWriteLock();
            }
        }
        public void AddOrIgnore(T1 key, T2 value)
        {
            rwlock.EnterWriteLock();
            try
            {
                if (!mCache.ContainsKey(key))
                    mCache.Add(key, value);
            }
            finally
            {
                rwlock.ExitWriteLock();
            }
        }
        public void AddOrReplace(T1 key, T2 value)
        {
            rwlock.EnterWriteLock();
            try
            {
                if (!mCache.ContainsKey(key))
                    mCache.Add(key, value);
                else
                    mCache[key] = value;
            }
            finally
            {
                rwlock.ExitWriteLock();
            }
        }
        public bool Remove(T1 key)
        {
            bool result = false;
            rwlock.EnterWriteLock();
            try
            {
                result = mCache.Remove(key);
            }
            finally
            {
                rwlock.ExitWriteLock();
            }
            return result;
        }

        public void Clear()
        {
            rwlock.EnterWriteLock();
            try
            {
                mCache.Clear();
            }
            finally
            {
                rwlock.ExitWriteLock();
            }
        }

        public ReadOnlyCollection<T1> Keys
        {
            get
            {
                ReadOnlyCollection<T1> result;
                rwlock.EnterReadLock();
                try
                {
                    result = new ReadOnlyCollection<T1>(new List<T1>(mCache.Keys));
                }
                finally
                {
                    rwlock.ExitReadLock();
                }
                return result;
            }
        }
    }
}
